Inanimata
Night falls and lights across the city come to life. Some turn on immediately, some blink – on, off, on, off, and on again. What first appears to be a flicker is, at a second glance, less random. Street lights, lamps, headlights, lanterns—silent witnesses to the goings on around them—now broadcast what they have seen, through Morse code.
The curious were invited to seek out these blinking automata on the streets of Sydney, slow down and tune in to stories silently received and translated by the iOS app, Light Conversation, available for free download in the app store.



The app also enabled people to send morse code messages to each other using their flash. This project has had an unexpected life beyond this artwork with people all around the world using it for their own projects.
Information on how to hack your own lights is available below.
Special thanks to:
Lucy Parakhina for documentation,
Tobio for music in video,
and Matt Ward for the use of his antique shop Drunk on the Moon.


How to hack your own lights:
The morse code broadcaster runs on an Arduino micro-controller. You will need one with an operating voltage of 5v as opposed to 3.3v to drive the solid state relays referenced below. The code for this can be found below (simply replace the text at the top with your own). In some cases you could use the same power source used for the lights as the Arduino, but I typically use a separate 9v battery or USB power supply to keep things simple.
Please note that you do any of this wiring at your own risk. Although I have used this with many kinds of lights they have all so far all been powered by one of the following options (each uses the same code but requires a slightly different circuit):
-
240v mains (regular Australian power point, other countries may use 120v). For this I use an AC solid state relay like this one . Simply connect the Arduino ground and output pin to the input and use the output to interrupt the power or neutral going to the lamp. It does not matter which way around the output is wired. An easy way to do this is by cutting just one of the cables in an extension cord running to the light. Be careful and make sure not to have anything plugged in when making connections as this is enough voltage to kill you :)
-
12v car or motorcycle type battery. For this I use a DC solid state relay like this one . Simply connect the Arduino ground and output pin to the input and use the output to interrupt the power or ground to the lamp. It does matter which way around the output is wired. I interrupted the ground wire coming from a car headlight. In this case the positive output is connected to the the wire going to the lamp whilst the negative output is connected to the wire going to the battery. If I had interrupted the power going to the lamp then the positive would have been wired to the battery and the negative to the light. I have also used 12v batteries for LED lights.
-
5v output from Arduino. In this case you may be working with standard LEDs, which can be connected as per this Arduino tutorial .
/*
This work by René Christen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License:
http://creativecommons.org/licenses/by-nc-sa/4.0/
*/
String msg = "Replace this with your text.";
int outputPin = 12;
int unit = 300;//milliseconds
/*
UNIT LENGTHS
dot = 1
dash = 3
char gap space = 1
letter gap = 3
word gap = 7
*/
int offset = 33;//lowest ascii val
String db[63];//96 - offset (highest ascii val is 95)
//---------------------------------------------------------------
void setup() {
Serial.begin(9600);
initDB();
pinMode(outputPin, OUTPUT);
digitalWrite(outputPin, LOW);
}
//---------------------------------------------------------------
void loop() {
for (int i=0; i<msg.length(); i++)
{
Serial.println(msg[i]);//print letter to serial
if (msg[i] == ' ') {//if space in message
low();
delay((7-3) * unit);//word delay - letter delay already made after each letter
} //end if space in message
else
{
String morse = getMorseString(msg[i]);
Serial.println(getMorseString(msg[i]));//print letter to serial
for (int j=0; j<morse.length(); j++)
{
char c = morse[j];
if (c == '.')
{
high();
delay(1 * unit);
}
else if (c == '-')
{
high();
delay(3 * unit);
}
//in between letter gap:
low();
delay(1 * unit);
}//end for j / morse string
//letter gap:
low();
delay(3 * unit);
}//end else not space
}//end i / entire message
//word gap at message end:
low();
delay((7-3) * unit);//word delay - letter delay made after last letter
}
//---------------------------------------------------------------
void high() {
digitalWrite(outputPin, HIGH);
}
void low() {
digitalWrite(outputPin, LOW);
}
//---------------------------------------------------------------
String getMorseString(char _index) {
int index = (int) _index;
if (index <= 90 || index == 95) {
return db[index - offset];
} else { //change lower to upper case
return db[index - offset - 32];
}
}
//---------------------------------------------------------------
void initDB() {
//other chars start at 33
db[33 -offset]="-.-.--"; // !
db[34 -offset]=".-..-."; // "
db[36 -offset]="...-..-"; // $
db[38 -offset]=".-..."; // &
db[39 -offset]=".----."; // '
db[40 -offset]="-.--."; // (
db[41 -offset]="-.--.-"; // )
db[43 -offset]=".-.-."; // +
db[44 -offset]="--..--"; // ,
db[45 -offset]="-....-"; // -
db[46 -offset]=".-.-.-"; // .
db[47 -offset]="-..-."; // /
db[58 -offset]="---..."; // :
db[59 -offset]="-.-.-."; // ;
db[61 -offset]="-...-"; // =
db[63 -offset]="..--.."; // ?
db[64 -offset]=".--.-."; // @
db[95 -offset]="..--.-"; // _
//numeric chars start at ascii 48
db[(int) '0' -offset]="-----"; // 0
db[(int) '1' -offset]=".----"; // 1
db[(int) '2' -offset]="..---"; // 2
db[(int) '3' -offset]="...--"; // 3
db[(int) '4' -offset]="....-"; // 4
db[(int) '5' -offset]="....."; // 5
db[(int) '6' -offset]="-...."; // 6
db[(int) '7' -offset]="--..."; // 7
db[(int) '8' -offset]="---.."; // 8
db[(int) '9' -offset]="----."; // 9
//alphabetic chars start at ascii 65 for upper - end at 90, 97 for lower case - end at 122
db[(int) 'A' -offset]=".-"; // a
db[(int) 'B' -offset]="-..."; // b
db[(int) 'C' -offset]="-.-."; // c
db[(int) 'D' -offset]="-.."; // d
db[(int) 'E' -offset]="."; // e
db[(int) 'F' -offset]="..-."; // f
db[(int) 'G' -offset]="--."; // g
db[(int) 'H' -offset]="...."; // h
db[(int) 'I' -offset]=".."; // i
db[(int) 'J' -offset]="-..."; // j
db[(int) 'K' -offset]="-.-"; // k
db[(int) 'L' -offset]=".-.."; // l
db[(int) 'M' -offset]="--"; // m
db[(int) 'N' -offset]="-."; // n
db[(int) 'O' -offset]="---"; // o
db[(int) 'P' -offset]=".--."; // p
db[(int) 'Q' -offset]="--.-"; // q
db[(int) 'R' -offset]=".-."; // r
db[(int) 'S' -offset]="..."; // s
db[(int) 'T' -offset]="-"; // t
db[(int) 'U' -offset]="..-"; // u
db[(int) 'V' -offset]="...-"; // v
db[(int) 'W' -offset]=".--"; // w
db[(int) 'X' -offset]="-..-"; // x
db[(int) 'Y' -offset]="-.--"; // y
db[(int) 'Z' -offset]="--.."; // z
}